SNFPlayer = { }		-- public interface object

local SNFPlayerAlias = { }  -- private data object
local SNFPlayerCounts = { } -- not saved, but used as a cache to save lookup counts
local SNFPlayerRoles = { }
local pd = { } -- private data object

local SNFRoles = { }
SNFRoles["P"] = "Physical"
SNFRoles["T"] = "Tank"
SNFRoles["H"] = "Healer"
SNFRoles["C"] = "Caster"


local function tcontainsplayer(table, name)

	-- Make sure name is translated before it's passed into this method.
	for _, val in ipairs(table) do

		--SNFDEBUG(2, "Checking SNFPlayer:GetPlayerMain("..(val or "nil")..") = "..SNFPlayer:GetPlayerMain(val).." to "..(name or "nil"))
		if SNFPlayer:GetPlayerMain(val) == name then return true end
	end
	return false
end

function SNFPlayer:GetPlayerMain(name)

	if pd and pd[name] and pd[name]["main"] then return pd[name]["main"] end

	if SNFPlayerAlias and SNFPlayerAlias[name] then return SNFPlayerAlias[name] end

	--SNFDEBUG(2, "Returning translated name: "..(name or "nil").." to "..(SNFPlayerAlias[name] or "nil") )
	return name
end

function SNFPlayer:AddAlias(main, alt)

	local realname = SNFPlayer:GetPlayerMain(main)

	if not realname then
		SNFDEBUG(1, "Failed to get main name for "..main.."!")
		return false
	end

	if not alt then
		SNFDEBUG(0, "You must provide an alias name")
		return false
	end

	SNFPlayerAlias[alt] = realname
	return true
end

function SNFPlayer:RemoveAlias(alt)

	if not alt then
		SNFDEBUG(0, "You must provide an alias name")
		return false
	end

	if not (SNFPlayerAlias and SNFPlayerAlias[name]) then
		SNFDEBUG(0, "That alias does not exist")
		return false
	end

	SNFPlayerAlias[alt] = nil
	return true
end

function SNFResetPlayerData()
	pd = { }
	SNFPlayerRoles = { }
end

function SNFCheckGuildRosterInfo()
	local done = false
	local updates = false
	local i

	i = 1

	SNFDEBUG(4, "GuildRoster Update received")
	while not done do
		local name, rank, rankIndex, level, class, zone, note, officernote, online, status, classFileName = GetGuildRosterInfo(i);
		if name then
			if not pd[name] then
				--SNFDEBUG(2, "Adding guild member: "..name.." rank "..rank)
				pd[name] = { }
				pd[name]["rank"] = rank
				pd[name]["onote"] = officernote
				main = strmatch(officernote, ".*%[(.*)%].*")
				if main then
					pd[name]["main"] = main
					pd[name]["rank"] = "Alt" -- overwrite, because some leader alts are high rank
					--SNFDEBUG(3, "Found main of "..main.." for "..name)
				end
				local role = strmatch(officernote, ".*%{(.*)%}.*")
				if role then
					role = strupper(role)
					if strlen(role) > 1 and strsub(role, 2,2) == "+" then
						role = strsub(role, 1, 1)
						if SNFRoles[role] then
							SNFDEBUG(0, (name or "nil").." leads "..SNFRoles[role])
							pd[name]["leads"] = role
						else
							SNFDEBUG(2, "Unsupported role leader abbreviation '"..(role or "Nil").."'")
						end
					end
					local _, ranknum = SNFGetPlayerRankAbbreviation(name)
					if ranknum < 2 then
						--SNFDEBUG(3, "Player "..(name or "nil").." is "..(role or "nil"))
						if not SNFPlayerRoles[role] then SNFPlayerRoles[role] = { } end
						tinsert(SNFPlayerRoles[role], name)
						updates = true
					end
				end

			end
		else
			done = true
		end
		i = i + 1
	end
	if updates then

		SNFDEBUG(2, "Roles updated:")
		for r, rname in pairs(SNFRoles) do
			local out = nil
			if SNFPlayerRoles[r] then
				for i, name in ipairs(SNFPlayerRoles[r]) do
					if out then
						out = out..", "
					else
						out = SNFRoles[r]..": "
					end
					out = out..(SNFPlayerRoles[r][i] or "nil")
				end
				SNFDEBUG(2, out)
			end
		end
	end
--	local name = GetUnitName("player")
end


function SNFGetPlayerRank(name)
	if not pd[name] then
		SNFDEBUG(3, "Can't find data for "..name..".  Initiating a scan of the guild roster.")
		GuildRoster()
		return "Unknown"
	end

	if not pd[name] then return "NotGuild" end

	return pd[name]["rank"]
end

-- returns a rank abbreviation and a ranking (used for sorting)
-- also used by role determination, as ranks 2+ are not considered raiding ranks.
function SNFGetPlayerRankAbbreviation(name)

	local r = SNFGetPlayerRank(name)

	SNFDEBUG(4, "Rank returned is "..r)

	if r == "Unknown" then
		return "U", 4
	elseif r == "NotGuild" then
		return "N", 5
	elseif r == "Raid Initiate" then
		return "I", 1
	elseif r == "Raider" or r == "Role Leader" or r == "Officer" or r == "Guild Mistress" then
		return "R", 0
	elseif r == "Veteran" then
		return "R", 0
	elseif r == "Member" or r == "PVP Member" then
		return "M", 2
	elseif r == "Alt" then
		return "A", 2
	else
		SNFDEBUG(1, "Rank not translated: "..r)
	end
	return r, 4
end

function SNFPlayer:ArePlayerCountsCached(name)

	return SNFPlayerCounts and SNFPlayerCounts[name] ~= nil
end

function SNFPlayer:GetPlayerCounts(name)

	if not (SNFPlayerCounts and SNFPlayerCounts[name]) then
		return 0,0,0
	end

--	SNFDEBUG(2, "Getting player counts:"..name..": "..SNFPlayerCounts[name]["Attend"]..","..SNFPlayerCounts[name]["Raids"]..","..SNFPlayerCounts[name]["DKP"])

	return SNFPlayerCounts[name]["Attend"] or 0, SNFPlayerCounts[name]["Raids"] or 0, SNFPlayerCounts[name]["DKP"] or 0
end

function SNFPlayer:SetPlayerCounts(name, nAttend, nRaids, nDKP)

	if not SNFPlayerCounts then SNFPlayerCounts = { } end

	if not SNFPlayerCounts[name] then SNFPlayerCounts[name] = { } end

	SNFDEBUG(2, "Setting player counts:"..name..": "..nAttend..","..nRaids..","..nDKP)
	SNFPlayerCounts[name]["Attend"] = nAttend
	SNFPlayerCounts[name]["Raids"] = nRaids
	SNFPlayerCounts[name]["DKP"] = nDKP
end

function SNFPlayer:ClearPlayerCounts(name)

	if not SNFPlayerCounts then SNFPlayerCounts = { } end

	SNFPlayerCounts[name] = nil
	SNFDEBUG(2, "Player counts for "..(name or "nil").." cleared!")
end

function SNFPlayer:ClearAllPlayerCounts()

	SNFPlayerCounts = { }
	SNFDEBUG(2, "All Player counts cleared!")
end

function SNFPlayer:FindOnlineAlt(main)



end


function SNFPlayer:GetRoleofLeader(name)
	if not pd[name] then
		SNFDEBUG(0, (name or "nil").."'s player data is not initialized when looking for lead role.")
		return ""
	end
	return pd[name]["leads"];
end

function SNFPlayer:GetPlayersForRole(role)

	if not (SNFPlayerRoles and SNFPlayerRoles[role]) then return { } end
	return  SNFPlayerRoles[role]
end

--Assumes name is already translated to a realname
function SNFPlayer:GetPlayerDKP(name)

	SNFDEBUG(2, "Getting player dkp:"..name)

	if SNFPlayerCounts and SNFPlayerCounts[name] and SNFPlayerCounts[name]["DKP"] then
		return SNFPlayerCounts[name]["DKP"]
	end

	--Otherwise, recalc DKP
	local srt = SNFFilter:GetBaseListFromType("attend")

	SNFDEBUG(0, "Attend List is "..(#(srt) or "nil").." items long")

	local nRaids, nAttend, nDKP = 0,0,0

	for _, DATE in ipairs(srt) do

		local AttendData = SNFAttend:GetBaseAttendList()
		local data = AttendData[DATE]
		local count_wait, count_in = 0, 0

--		SNFDEBUG(3, "Checking date: "..(DATE or "nil"))
--		if not data or not data["start_in"] then
--			SNFDEBUG(3, "Raid doe not have a start_in: "..(DATE or "nil"))
--		end

		if data and data["start_in"] and tcontainsplayer(data["start_in"], name) then
			count_in = count_in + 1
		elseif data and data["start_wait"] and tcontainsplayer(data["start_wait"], name) then
			count_wait = count_wait + 1
		end
		nRaids = nRaids + 1

		-- Notice that an "attendcredit" modifier will cause end not to be listed or counted.
		-- Also, if end_in isn't recorded yet, the current raid will only count start
		if not data["attendcredit"] and data["end_in"] then
			if data and data["end_in"] and tcontainsplayer(data["end_in"], name) then
				count_in = count_in + 1
			elseif data and data["end_wait"] and tcontainsplayer(data["end_wait"], name) then
				count_wait = count_wait + 1
			end
			nRaids = nRaids + 1
		end
		nAttend = nAttend + count_in + count_wait
		if count_wait == 2 then
			nDKP = nDKP + 1 -- if you're only on wait list for a night, then you only get 1 DKP
		else
			nDKP = nDKP + count_in + count_wait -- otherwise you get up to 2 DKP.
		end
	end

	SNFDEBUG(0, "Data: raids: "..nRaids.." attend: "..nAttend.." DKP: "..nDKP)
	--Save data into cache
	if not SNFPlayerCounts then SNFPlayerCounts = { } end
	if not SNFPlayerCounts[name] then SNFPlayerCounts[name] = { } end

	SNFPlayerCounts[name]["DKP"] = nDKP
	return nDKP
end